package com.hmdp.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.Blog;
import com.hmdp.entity.ScrollPage;
import com.hmdp.entity.User;
import com.hmdp.mapper.BlogMapper;
import com.hmdp.service.IBlogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IUserService;
import com.hmdp.utils.SystemConstants;
import com.hmdp.utils.UserHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
    @Autowired
    private IUserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result queryBlogById(Long id) {
        Blog blog = getById(id);
        if (blog == null) {
            return Result.fail("笔记不存在！");
        }
        return Result.ok(blog);
    }

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(this::queryBlogUser);
        return Result.ok(records);
    }

    @Override
    public Result likeBlog(Long id) {
        UserDTO user = UserHolder.getUser();
        String key = "blog:liked:" + id;
        String key1 = "blog:likes:" + id;
        String userId = user.getId().toString();
        if (user == null){
            return Result.fail("请先登录");
        }
        if (Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(key, userId))){
            stringRedisTemplate.opsForSet().remove(key, userId);
            stringRedisTemplate.opsForZSet().remove(key1,userId);
            update().setSql("liked = liked - 1").eq("id", id).update();
            return Result.ok();
        }
        update().setSql("liked = liked + 1").eq("id", id).update();
        stringRedisTemplate.opsForSet().add(key,user.getId().toString());
        stringRedisTemplate.opsForZSet().add(key1,userId,System.currentTimeMillis());
        return Result.ok();
    }

    public void queryBlogUser(Blog blog) {
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            blog.setIsLike(false);
            return;
        }
        Long userId = blog.getUserId();
        blog.setIcon(userService.getById(userId).getIcon());
        blog.setName(userService.getById(userId).getNickName());
        if(Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(
                "blog:liked:" + blog.getId(),
                user.getId().toString()))){
            blog.setIsLike(true);
        }else blog.setIsLike(false);
    }

    @Override
    public Result queryBlogLikes(Long id) {
        List<UserDTO> users = stringRedisTemplate.opsForZSet().range(
                "blog:likes:" + id,
                0,
                4
        ).stream().map(userId -> {
            User user = userService.getById(userId);
            UserDTO userDTO = new UserDTO();
            userDTO.setId(user.getId());
            userDTO.setIcon(user.getIcon());
            userDTO.setNickName(user.getNickName());
            return userDTO;
        }).collect(Collectors.toList());
        return Result.ok(users);
    }

    @Override
    public Result queryBlogByFollow(Long lastId, Integer offset) {
        // 初始化分页结果对象
        ScrollPage<Blog> page = new ScrollPage<>();

        // 1. 获取当前登录用户
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.fail("请先登录");
        }

        // 2. 从Redis有序集合中分页查询关注的博客ID（按时间倒序）
        String key = "feed:" + user.getId(); // Redis键格式：feed:用户ID
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(key, 0, lastId, offset, 3); // 参数说明：key, 最小分数, 最大分数, 偏移量, 数量

        // 处理空结果
        if (typedTuples == null || typedTuples.isEmpty()) {
            return Result.ok();
        }

        // 3. 解析Redis查询结果
        Long minTime = 0L;  // 记录当前批次的最小时间戳（用于分页）
        int repeat = 1;     // 记录连续相同时间戳的数量（用于偏移量计算）
        page.setList(new ArrayList<>(typedTuples.size()));
        List<Long> ids = new ArrayList<>(typedTuples.size()); // 收集博客ID

        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            String blogId = tuple.getValue();  // 获取博客ID
            Long time = tuple.getScore().longValue(); // 获取时间戳（分数）

            ids.add(Long.valueOf(blogId));

            // 计算连续相同时间戳的数量（处理同一时间多条数据的情况）
            if (time.equals(minTime)) {
                repeat++;
            } else {
                minTime = time;
                repeat = 1;
            }
        }

        // 4. 根据ID批量查询博客详情（保持Redis中的顺序）
        String idsStr = StrUtil.join(",", ids);
        List<Blog> blogs = query()
                .in("id", ids) // WHERE id IN (id1, id2...)
                .last("ORDER BY FIELD(id," + idsStr + ")") // 按指定ID顺序排序
                .list();

        // 5. 补充博客的作者信息
        for (Blog blog : blogs) {
            queryBlogUser(blog); // 填充用户信息
            page.getList().add(blog);
        }

        // 6. 设置分页参数
        page.setOffset(repeat);  // 下一次查询的偏移量
        page.setMinTime(minTime); // 下一次查询的最大时间戳

        return Result.ok(page);
    }
}
